package com.gavin.security;

import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

public class DES {

	// 静态对象,所有static在此声明并初始化------------------------------------------------------------------------

	// 内部对象,所有在本类中创建并使用的对象在此声明--------------------------------------------------------------
	protected javax.crypto.Cipher cipherEncode = null;
	protected javax.crypto.Cipher cipherDecode = null;

	// 属性对象,所有在本类中创建，并允许外部访问的对象在此声明并提供get/set方法-----------------------------------

	// 引用对象,所有在外部创建并传入使用的对象在此声明并提供set方法-----------------------------------------------

	// 内部方法,所有仅在本类或派生类中使用的函数在此定义为protected方法-------------------------------------------

	// 公共方法,所有可提供外部使用的函数在此定义为public方法------------------------------------------------------
	public void init(String strKey, String strIV) {
		byte[] bysKey = null;
		byte[] bysIV = null;

		if (strKey.length() < 8) {
			throw new RuntimeException("Key length must be at least 8");
		}
		if (strIV != null && strIV.length() < 8) {
			throw new RuntimeException("IV length must be at least 8");
		}

		try {
			bysKey = strKey.getBytes("utf-8");
			if (strIV != null) {
				bysIV = strIV.substring(0, 8).getBytes("utf-8");
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		this.init(bysKey, bysIV);
	}

	public void init(byte[] bysKey, byte[] bysIV) {
		if (bysKey == null) {
			throw new RuntimeException("Key cannot be null");
		}

		try {
			SecretKey key = null;
			DESKeySpec desKeySpec = null;

			desKeySpec = new javax.crypto.spec.DESKeySpec(bysKey);
			SecretKeyFactory skf = javax.crypto.SecretKeyFactory.getInstance("DES");
			key = (javax.crypto.SecretKey) skf.generateSecret(desKeySpec);

			desKeySpec = new DESKeySpec(bysKey);
			AlgorithmParameterSpec iv = null;
			if (bysIV == null) {
				this.cipherEncode = javax.crypto.Cipher.getInstance("DES");
				this.cipherEncode.init(javax.crypto.Cipher.ENCRYPT_MODE, key);

				this.cipherDecode = javax.crypto.Cipher.getInstance("DES");
				this.cipherDecode.init(javax.crypto.Cipher.DECRYPT_MODE, key);
			} else {
				iv = new IvParameterSpec(bysIV);
				this.cipherEncode = javax.crypto.Cipher.getInstance("DES/CBC/PKCS5Padding");
				this.cipherEncode.init(javax.crypto.Cipher.ENCRYPT_MODE, key, iv);

				this.cipherDecode = javax.crypto.Cipher.getInstance("DES/CBC/PKCS5Padding");
				this.cipherDecode.init(javax.crypto.Cipher.DECRYPT_MODE, key, iv);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public void setKey(byte[] bysKey) {
		this.init(bysKey, null);
	}

	public void setKey(byte[] bysKey, byte[] bysIV) {
		this.init(bysKey, bysIV);
	}

	/**
	 * 加密
	 * 
	 * @param bysInput
	 * @return
	 * @throws Exception
	 */
	public byte[] encode(byte[] bysInput) {
		try {
			byte[] bysOutput = null;
			synchronized (this.cipherEncode) {
				bysOutput = this.cipherEncode.doFinal(bysInput);
			}

			return bysOutput;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public String encode(String strInput) {
		try {
			byte[] bysData = this.encode(strInput.getBytes("utf-8"));
			String strData = Base64.encode(bysData);

			return strData;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 解密
	 * 
	 * @param bysInput
	 * @return
	 * @throws Exception
	 */
	public byte[] decode(byte[] bysInput) {
		try {
			byte[] bysOutput = null;
			synchronized (this.cipherDecode) {
				bysOutput = this.cipherDecode.doFinal(bysInput);
			}

			return bysOutput;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 解密
	 * 
	 * @param strInput
	 *            16进制字符串
	 * @return
	 */
	public String decode(String strInput) {
		try {
			byte[] bysInput = Base64.decode(strInput);
			byte[] bysData = this.decode(bysInput);
			String strData = new String(bysData, "utf-8");

			return strData;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 加密
	 * 
	 * @param bysInput
	 * @return
	 * @throws Exception
	 */
	public byte[] encrypt(byte[] bysInput) {
		try {
			byte[] bysOutput = null;
			synchronized (this.cipherEncode) {
				bysOutput = this.cipherEncode.doFinal(bysInput);
			}

			return bysOutput;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 解密
	 * 
	 * @param bysInput
	 * @return
	 * @throws Exception
	 */
	public byte[] decrypt(byte[] bysInput) {
		try {
			byte[] bysOutput = null;
			synchronized (this.cipherDecode) {
				bysOutput = this.cipherDecode.doFinal(bysInput);
			}

			return bysOutput;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	// 接口实现,所有实现接口函数的实现在此定义--------------------------------------------------------------------

	// 事件处理,所有重载派生类的事件类方法(一般为on...ed)在此定义-------------------------------------------------

	// 事件定义,所有在本类中定义并调用，由派生类实现或重载的事件类方法(一般为on...ed)在此定义---------------------

	// 构造函数,所有构造函数在此定义------------------------------------------------------------------------------

	public DES() {
		super();

		// 请在此加入初始化代码,内部对象和属性对象负责创建或赋初值,引用对象初始化为null，初始化完成后在设置各对象之间的关系
	}

//	public static void main(String[] args) {
//
//		String strText = "1234567890abcdefg";
//
//		DES test = new DES();
//		test.init("http://www.dafy.com/index.htm", null);
//
//		String strEncoded = null;
//		String strDecoded = null;
//		long lStartTime = System.currentTimeMillis();
//		for (int i = 0; i < 1; i++) {
//			strEncoded = test.encode(strText.toString());
//		}
//		long lDelay = System.currentTimeMillis() - lStartTime;
//		System.out.println(strEncoded);
//		System.out.println("Delay: " + lDelay);
//
//		// strEncoded="XKicls2yrqoaBc2gRZkLjL/fv1Cbh7ZzMAppFjG5FN1vNpmH19u2gA4sO+bsmYaDDS6MlU9DizxhTCVv/byst1zOsNjc7ab2IWY/rEVQ34p67pmI2w8cvhGb/ZVe38Po84soJm1W1izWJBsGYR/7n9Bd3JdIY0RqzFMBS9GqzVcFFz8fX4bZTTNeTxG8fO5FYo+DTpc/pR1ghhpJg6wSH2o1CEX9rIY+48GBEM6VzeytWm2juB5H68X6I2/aG6aAiFkDZQIMSUpFZr41CASg0P3Fy7dD3KH696GvAdhSDPLnTJxf02p6DFpo0KlOq3y3HJ6h1FEzIiJCh3Nwx1HGTDuEGxYRCwcoj7eHKWHK2fLUduzsvca6e/txgzLW1QHi";
//		lStartTime = System.currentTimeMillis();
//		for (int i = 0; i < 1; i++) {
//			strDecoded = test.decode(strEncoded);
//		}
//		lDelay = System.currentTimeMillis() - lStartTime;
//
//		System.out.println("Delay: " + lDelay);
//	}
}
